package WebGamble;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.awt.BorderLayout;
import javax.swing.JPanel;

public class PCEggs extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	static String BaseURL = "http://www.pceggs.com/play/pg28Insert.aspx?LID=";
	static Random rand = new Random();

	static private HttpResponse httpResponse;
	static private DefaultHttpClient httpClient = new DefaultHttpClient();
	static public class showImg extends JPanel {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		JLabel jl = null;
		ImageIcon img = null;

		public showImg(InputStream bmpFile) throws IOException {
			img = new ImageIcon(ImageIO.read(bmpFile));
			jl = new JLabel(img);
			this.setLayout(new BorderLayout());
			this.add(jl, BorderLayout.CENTER);
		}
	}
	
	static public int GCD(int numA, int numB) {
		int gcd = 1;
		for (int k = 1; k <= numA && k <= numB; k++)
			if (numA % k == 0 && numB % k == 0)
				gcd = k;
		return gcd;
	}
	
	static public double min(double[] valList) {
		double val;
		val = valList[0];
		for(double value : valList) {
			if(value < val)
				val = value;
		}
		return val;
	}
	static public int MinLoc(double[] valList) {
		double val;
		val = valList[0];
		int i = 0, loc = 0;
		for(double value : valList) {
			if(value < val) {
				val = value;
				loc = i;
			}
			i++;
		}
		return loc;
	}
	
	static public double max(double[] valList) {
		double val;
		val = valList[0];
		for(double value : valList) {
			if(value > val)
				val = value;
		}
		return val;
	}
	
	static public int sum(int[] valList) {
		int val = 0;
		for(int value : valList)
			val += value;
		return val;
	}
	static public double sum(double[] valList) {
		double val = 0;
		for(double value : valList)
			val += value;
		return val;
	}
	
	static public double score1(double[] oddsList, int[] distribution) {
		double[] score = new double[28];
		double count = 0;
		double s = sum(distribution);
		for(int i = 0; i < 28; i++) {
			score[i] = oddsList[i] * distribution[i] - s;
			if(score[i] < 0)
				count += originDist[i];
		}
		return min(score) - count * 2;
	}
	static public int[] originDist = {1, 3, 6, 10, 15, 21, 28, 72, 90, 110, 126, 138, 146, 150, 150, 146, 138, 126, 110, 90, 72, 28, 21, 15, 10, 6, 3, 1};
//	static public int[] originDist = {1, 3, 6, 10, 15, 21, 28, 36, 45, 56, 63, 67, 71, 77, 77, 71, 67, 63, 56, 45, 36, 28, 21, 15, 10, 6, 3, 1};
	static public double total = sum(originDist);
	static public double score2(double[] oddsList, int[] distribution) {
		double[] score = new double[28];
		double count = 0;
		double s = sum(distribution);
		for(int i = 0; i < 28; i++) {
			score[i] = (oddsList[i] * distribution[i] - s) * originDist[i];
			if(score[i] < 0)
				count += 1;
		}
		return sum(score) / total - count * 1.1;
	}
	static public double score3(double[] oddsList, int[] distribution) {
		double[] score = new double[28];
		double s = sum(distribution);
		for(int i = 0; i < 28; i++) {
			score[i] = (oddsList[i] * distribution[i] - s) * originDist[i];
		}
		return sum(score) / total;
	}
	
	static public void optimize(double[] oddsList, int[] distribution) {
		double[] score = new double[28];
		double s = sum(distribution);
		for(int i = 0; i < 28; i++) {
			score[i] = (oddsList[i] * distribution[i] - s);
		}
		int loc;
		loc = MinLoc(score);
		distribution[loc]++;
		for(int i = 0; i < 28; i++) {
			if(score[i] >= 0 && score[i] <= 7) {
				distribution[i]++;
			}
		}
	}
	
	static public int[] baseDist = {2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2};
	
	static public int[] getNextDist(int[] distribution) {
		int[] nextDist = distribution.clone();
		int t = rand.nextInt(22) + 1;
		for(; t > 0; t--) {
			while(true) {
				int i = rand.nextInt(22) + 3;
				int step = 1;
				double flag = rand.nextDouble();
				if(flag < 0.5)
					step = -1;
				int temp = nextDist[i] + step; 
				if(temp >= baseDist[i]) {
					nextDist[i] = temp;
					break;
				}
			}
		}
		return nextDist;
	}
	static public int[] getNextDist0(int[] distribution) {
		int[] nextDist = distribution.clone();
		while(true) {
			int i = rand.nextInt(28);
			int step = 1;
			int temp = nextDist[i] + step; 
			if(temp >= baseDist[i]) {
				nextDist[i] = temp;
				break;
			}
		}
		return nextDist;
	}
	
	static public int showStatus(double[] oddsList, int[] distribution, int idx, boolean showFlag) {
		double[] score = new double[28];
		int s = sum(distribution);
		int count = 0;
		if(showFlag) {
			System.out.println(idx + "th step:");
			for(int i = 0; i < 28; i++) {
				System.out.printf("%d: %03d, ", i, distribution[i]);
			}
			System.out.println();
		}
		for(int i = 0; i < 28; i++) {
			score[i] = oddsList[i] * distribution[i] - s;
			if(score[i] < 0)
				count++;
			if(showFlag)
				System.out.printf("%d: %06f, ", i, score[i]);
		}
		if(showFlag) {
			System.out.println();
			System.out.println("Total negative: " + count);
			System.out.println("Min: " + min(score));
			System.out.println("Max: " + max(score));
			for(int i = 0; i < 28; i++)
				score[i] = score[i] * originDist[i];
			System.out.println("Avg: " + sum(score) / total);
			System.out.println("Num: " + s);
		}
		return count;
	}
	
	@SuppressWarnings("deprecation")
	public static void main(String[] args) throws ClientProtocolException, IOException, InterruptedException {
		HttpGet httpGet;
        httpGet = new HttpGet("http://www.pceggs.com/nologin.aspx");
		httpResponse = httpClient.execute(httpGet);
		String loginHtml = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
		httpGet.releaseConnection();
		
		httpGet = new HttpGet("http://www.pceggs.com/VerifyCode_Login.aspx?id=0." + Math.abs(rand.nextLong()));
        httpResponse = httpClient.execute(httpGet);
        JFrame pane = new JFrame("Image Pane");
        pane.getContentPane().add(new showImg(httpResponse.getEntity().getContent()));
        pane.pack();
        pane.setVisible(true);
        httpGet.releaseConnection();
        System.out.println("Please enter the verify code:");
        String VerifyCode;
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        VerifyCode = reader.readLine();
		
		Document loginDoc = Jsoup.parse(loginHtml);
		String loginURL = "http://www.pceggs.com/nologin.aspx";
		Elements loginInputs = loginDoc.select("input");
        HttpPost httpPost = new HttpPost(loginURL);
        List <NameValuePair> params = new ArrayList <NameValuePair>();
		for(Element input : loginInputs) {
			if(input.attr("type").compareToIgnoreCase("password") == 0) {
				input.attr("name", "txt_PWD");
				input.val("qazxcdews123321");
			}
			else if(input.attr("name").compareToIgnoreCase("email") == 0) {
				input.attr("name", "txt_UserName");
				input.val("365064421@qq.com");
			}
			else if(input.attr("name").compareToIgnoreCase("txt_VerifyCode") == 0) {
				input.val(VerifyCode);
			}
			else if(input.attr("name").compareToIgnoreCase("FromUrl") == 0) {
				input.val("http://www.pceggs.com/play/pc28.aspx");
			}
			else if(input.attr("name").compareToIgnoreCase("Login_Submit") == 0) {
				input.attr("name", "Login_Submit.x");
				input.val("32");
				params.add(new BasicNameValuePair(input.attr("name"), input.val()));
				System.out.println(input.attr("name") + ": " + input.val());
				input.attr("name", "Login_Submit.y");
				input.val("8");
				params.add(new BasicNameValuePair(input.attr("name"), input.val()));
				System.out.println(input.attr("name") + ": " + input.val());
				continue;
			}
			
			params.add(new BasicNameValuePair(input.attr("name"), input.val()));
			System.out.println(input.attr("name") + ": " + input.val());
		}
        httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
        httpResponse = httpClient.execute(httpPost);
        if(httpResponse.getStatusLine().getStatusCode() == 302) {
        	System.out.println("Login success...");
        }
        loginHtml = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
        //System.out.println(loginHtml);
        httpPost.releaseConnection();
        pane.dispose();
        
//        httpGet = new HttpGet("http://wap.pceggs.com/play/pc28.aspx");
//        httpResponse = httpClient.execute(httpGet);
//        String html = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
//        httpGet.releaseConnection();
//        Document document = Jsoup.parse(html);
//        Elements elements = document.select("li.kj_white_line:eq(5) a");
//        String gambleURL = elements.attr("href");
//        httpGet = new HttpGet(gambleURL);
//        httpResponse = httpClient.execute(httpGet);
//        html = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
//        httpGet.releaseConnection();
        
        int originTimes = 15, timesOfTimes = 2;
        int money = 0, prevMoney = 0, times = originTimes;
        int winCount = 0, loseCount = 0;
        int topCount = 0;
        
        while(true) {
            httpGet = new HttpGet("http://www.pceggs.com/play/pc28.aspx");
            httpResponse = httpClient.execute(httpGet);
            String html = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");

            httpGet.releaseConnection();
            Document document = Jsoup.parse(html);
            Elements elements = document.select("#panel tr:eq(5) td:eq(0)");
            int gambleId = Integer.parseInt(elements.get(0).text());
            elements = document.select("#panel tr:eq(5) td:eq(5) script");
            int lid = Integer.parseInt(elements.get(0).html().substring(12, 18));
            String gambleURL = BaseURL + lid;
            int i;
            double[] oddsList = new double[28];
            String odds;
          //int[] distribution = {1, 1, 1, 1, 1, 1, 2, 5, 5, 5, 25, 25, 25, 25, 25, 25, 25, 25, 5, 5, 5, 2, 1, 1, 1, 1, 1, 1};
//            int[] distribution = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
//            httpGet = new HttpGet("http://www.pceggs.com/play/pg28mode.aspx?refresh=" + (lid - 1));
//            httpGet.addHeader("X_REQUESTED_WITH", "XMLHttpRequest");
//            httpGet.addHeader("Referer", gambleURL);
//            httpResponse = httpClient.execute(httpGet);
//            odds = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
//            
//            
//            i = 0;
//            for(String value : odds.split(",")) {
//            	oddsList[i] = Double.parseDouble(value);
//            	i++;
//            }
//            httpGet.releaseConnection();
//            System.out.println();
        	
        	httpGet = new HttpGet("http://www.pceggs.com/play/pc28.aspx");
            httpResponse = httpClient.execute(httpGet);
            html = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
            httpGet.releaseConnection();
            document = Jsoup.parse(html);
            elements = document.select(".infro span:eq(3)");
            
            money = Integer.parseInt(elements.text().replaceAll(",", ""));
//            if(money < prevMoney) {
//            	winCount = 0;
//            	loseCount++;
//            }
//            else if(money > prevMoney) {
//            	loseCount = 0;
//            	winCount++;
//            }
//            times = 3;
//            if(winCount == 1) {
//            	times = 3;
//            }
//            else if(winCount >= 2) {
//            	times = 1;
//            }
//            else if(loseCount == 1) {
//            	times = 18;
//            	if(rand.nextDouble() >= 0.25)
//            		times = 36;
//            }
//            else if(loseCount >= 2) {
//            	times = 48;
//            }
//            prevMoney = money;
// version 2            
//	        if(money < prevMoney) {
//	        	if(winCount > 0) {
//	        		winCount = 0;
//	        		loseCount = 0;
//	        	}
//	        	loseCount++;
//	        }
//	        else if(money > prevMoney) {
//	        	winCount++;
//	        }
//	        if(money != prevMoney) {
//	        	if(winCount > loseCount && times >= originTimes * timesOfTimes) {
//	         		times /= timesOfTimes;
//	         	}
//	         	else if(winCount <= loseCount && times < originTimes * timesOfTimes * timesOfTimes * timesOfTimes * timesOfTimes) {
//	         		times *= timesOfTimes;
//	         	}
//	 	        if(times == originTimes * timesOfTimes * timesOfTimes * timesOfTimes * timesOfTimes) {
//	 	        	topCount++;
//	 	        	if(topCount > 4) {
//	 	        		topCount = 0;
//	 	        		times = originTimes;
//	 	        	}
//	 	        }
//	        }
// version 3
            times = 1;
            System.out.println("Current ID: " + gambleId);
            System.out.println("Current times: " + times);
            prevMoney = money;
            
            System.out.println("Current Money: " + money);
            Pattern p = Pattern.compile("GetRTime\\([0-9]+\\);"), p1 = Pattern.compile("[0-9]+");
            Matcher m = p.matcher(html);
            m.find();
            html = m.group();
            m = p1.matcher(html);
            m.find();
            int timeout = Integer.parseInt(m.group());
            if(timeout <= 3) {
            	System.out.println("Timeout...");
            	Thread.sleep(5000);
            	continue;
            }
            
//            elements = document.select("#panel tr:gt(5) script");
//            int[] history = new int[3];
//            for(i = 0; i < history.length; i++) {
//            	history[i] = Integer.parseInt(elements.get(i * 4).html().substring(26, 28)) - 10;
//            }
            
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
//            Thread.currentThread();
    		Thread.sleep((timeout - 3) * 1000);

    		long startT = System.currentTimeMillis(), endT;
            httpGet = new HttpGet("http://www.pceggs.com/play/pg28mode.aspx?refresh=" + lid);
            httpGet.addHeader("X_REQUESTED_WITH", "XMLHttpRequest");
            httpGet.addHeader("Referer", gambleURL);
            httpResponse = httpClient.execute(httpGet);
            odds = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
            i = 0;
            for(String value : odds.split(",")) {
            	oddsList[i] = Double.parseDouble(value);
            	System.out.print(oddsList[i] + ", ");
            	i++;
            }
            httpGet.releaseConnection();
//            System.out.println();
//            double[] gambleNum = new double[28];
//            for(i = 0; i < 28; i++) {
//            	gambleNum[i] = distribution[i] * oddsList[i];
//            }
//            System.out.print("min: ");
//            System.out.println(min(gambleNum) - sum(distribution));
//            System.out.print("max: ");
//            System.out.println(max(gambleNum) - sum(distribution));

            int looperLimit = 8;
            
            int[] finalDist = new int[28];
            double finalScore = -8, finalCount = 28;
            
            for(int looper = 0; looper < looperLimit; looper++) {
           	 //int[] distribution = {1, 1, 1, 1, 1, 1, 2, 5, 5, 5, 25, 25, 25, 25, 25, 25, 25, 25, 5, 5, 5, 2, 1, 1, 1, 1, 1, 1};
               int[] distribution = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
               double T, dE, r;
               T = sum(oddsList) * sum(distribution);
               r = 0.9;
               int[] nextDist;
               int score = showStatus(oddsList, distribution, i, false), nextScore = 0;
               int countFlag = 0;
               i = 0;
               while (countFlag < 5 || i < 4000) {
	       			nextDist = getNextDist(distribution);
//	       			optimize(oddsList, nextDist);
//        			optimize(oddsList, nextDist);
//        			optimize(oddsList, nextDist);
//        			optimize(oddsList, nextDist);
	       			dE = score2(oddsList, nextDist) - score2(oddsList, distribution);
	       			nextScore = showStatus(oddsList, distribution, i, false);
	       			if (dE > 0 && nextScore <= score) {
	
	       				distribution = nextDist.clone(); 
	       			}
	       			else {
	
	       				if (Math.exp(dE / T) > rand.nextDouble() * 3) {
	       					distribution = nextDist.clone();
	       					optimize(oddsList, distribution);
	       				}
	       			}
	       			
	       			if(score2(oddsList, nextDist) > finalScore/* && nextScore <= finalCount + 1*/ && nextScore <= 8) {
        				finalScore = score2(oddsList, nextDist);
        				finalCount = nextScore;
        				finalDist = nextDist.clone();
        				showStatus(oddsList, finalDist, i, false);
        			}
	       			
	       			T = r * T;
	       			i++;
	       			
	       			
	       			if(nextScore == score)
	       				countFlag++;
	       			else
	       				countFlag = 0;
	       			score = nextScore;
	       		}
               
           }
            
           if((!(score3(oddsList, finalDist) < 4) && !(finalCount >= 9)) || (!(score3(oddsList, finalDist) < 1) && !(finalCount >= 7))) {
        	   for(i = 0; i < 28; i++) {
            	   finalDist[i] *= times;
               }
                
                httpPost = new HttpPost("http://www.pceggs.com/play/pg28InsertDo.aspx");
                List <NameValuePair> gambleParams = new ArrayList <NameValuePair>();
                String temps = String.valueOf(finalDist[0]);
                int s = finalDist[0];
                for(i = 1; i < 28; i++) {
                	temps = temps + "," + finalDist[i];
                	gambleParams.add(new BasicNameValuePair("SMONEY", String.valueOf(finalDist[i])));
                	s += finalDist[i];
                }
                gambleParams.add(new BasicNameValuePair("ALLSMONEY", temps));
                Date date = new Date();
        		date.setMinutes((date.getMinutes() / 5 + 1) * 5);
        		gambleParams.add(new BasicNameValuePair("CTIME", df.format(date)));
        		gambleParams.add(new BasicNameValuePair("Cheat", "CAE"));
        		gambleParams.add(new BasicNameValuePair("LID", String.valueOf(lid)));
        		gambleParams.add(new BasicNameValuePair("SMONEYSUM", String.valueOf(s)));
        		gambleParams.add(new BasicNameValuePair("SMONEYY", "ALD"));
        		gambleParams.add(new BasicNameValuePair("_issue", String.valueOf(gambleId)));
        		gambleParams.add(new BasicNameValuePair("isdb_p", "0"));
        		gambleParams.add(new BasicNameValuePair("lastgain", ""));
//        		for(i = 0; i < gambleParams.size(); i++) {
//        			System.out.println(gambleParams.get(i).getName() + ": " + gambleParams.get(i).getValue());
//        		}
        		httpPost.setEntity(new UrlEncodedFormEntity(gambleParams, HTTP.UTF_8));
        		httpPost.addHeader("Host", "www.pceggs.com");
        		httpPost.addHeader("Referer", gambleURL);
        		httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/18.0");
                httpResponse = httpClient.execute(httpPost);
                html = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
                httpPost.releaseConnection();
                
                endT = System.currentTimeMillis();
                showStatus(oddsList, finalDist, 0, true);
                System.out.println("Running time: " + (endT - startT) / 1000 + "s");
                System.out.println();

           }
           else {
        	   System.out.println();
        	   System.out.print("Avg = " + score3(oddsList, finalDist) + ", ");
        	   System.out.print("Total negative = " + finalCount + ", exit...");
        	   System.out.println();
        	   System.out.println();
           }
			
           
           Thread.sleep(50000);
            
        }
        
	}
}
